import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { Common } from "UtilsCommon";
import { useGetDataSourceOptions } from 'UseHooks';
import { Tree } from "antd";
import Base from './base';

const getTreeNode = (property, parentValue) => {
  Base.setValueTextName(property);
  const { parentValueName, valueName, textName } = property;

  const dataList = property.dataSource.filter(f => Common.isEquals(f[parentValueName], parentValue));

  const nodeList = []; let node = null; let children = null;

  const childKeys = [];
  dataList.forEach(m => {
    const value = m[valueName];
    const parentValue = m[parentValueName];
    node = { title: m[textName], key: value, value, parentValue };
    childKeys.push(value);
    children = getTreeNode(property, value);
    if (children.length > 0) node.children = children;
    nodeList.push(node);
  });

  property.nodeKeys[parentValue] = childKeys;

  return nodeList;
};

const getOptions = (property, view, pageAxis, parentValue) => {
  if (property.isOptionDataSource) return property.dataSource;
  property.nodeKeys = {};
  return getTreeNode(property, property.rootValue);
};

const getValuetToTreeNode = (property, node, selectedKeys) => {
  const { valueName, textName, checkedName, checkedValue, childName } = property;
  let blSelected = Common.isEquals(node[checkedName], checkedValue);

  const treeNode = { title: node[textName], key: node[valueName] };

  if (Common.isArray(node[childName]) && node[childName].length > 0) {
    treeNode.children = node[childName].map(m => getValuetToTreeNode(property, m, selectedKeys));

    if (blSelected) {
      for (let i = 0; i < treeNode.children.length; i++) {
        if (!treeNode.children[i].selected) { blSelected = false; break; }
      }
    }
  }

  if (blSelected) selectedKeys.push(node[valueName]);

  treeNode.selected = blSelected;

  return treeNode;
};

const setTreeNodesValue = (property, obj, value, setOptions, setSelectedKeys) => {
  obj.treeNodesValue = value;
  if (!Common.isArray(value) && !Common.isObject(value)) return;

  if (property.isNotRoot) value = value[property.childName];

  const list = Common.isArray(value) ? value : [value];

  const selectedKeys = [];
  const options = list.map(m => getValuetToTreeNode(property, m, selectedKeys));
  setOptions(options);
  setSelectedKeys(selectedKeys);
};

const setTreeNodeChecked = (property, node, value) => {
  const { valueName, unCheckedValue, checkedName, checkedValue, childName } = property;

  const v = Common.arrayFirst(value, (f) => Common.isEquals(f, node[valueName]));
  let blSelected = v !== null;

  const children = node[childName];
  if (Common.isArray(children) && children.length > 0) {
    children.map(m => setTreeNodeChecked(property, m, value));

    if (!blSelected) {
      for (let i = 0; i < children.length; i++) {
        if (Common.isEquals(children[i][checkedName], checkedValue)) {
          blSelected = true;
          break;
        }
      }
    }
  }

  node[checkedName] = blSelected ? checkedValue : unCheckedValue;
};

const getTreeNodesValue = (property, treeNodesValue, value) => {
  if (Common.isArray(treeNodesValue)) treeNodesValue.forEach(m => setTreeNodeChecked(property, m, value));
  else if (Common.isObject(treeNodesValue)) setTreeNodeChecked(property, treeNodesValue, value);

  return treeNodesValue;
};

const getSelectTreeNode = (options, selectedKeys) => {
  if (selectedKeys.length === 0) return null;

  let selectNode = null;
  for (let i = 0; i < options.length; i++) {
    if (options[i].key === selectedKeys[0]) {
      selectNode = options[i];
      selectNode.nodeIndex = i + 1;
      break;
    }
    else if (options[i].children) {
      selectNode = getSelectTreeNode(options[i].children, selectedKeys);
      if (selectNode !== null) break;
    }
  }

  return selectNode;
};

const getParentNodeKeys = (list, expandedKeys) => {
  list.forEach(d => {
    if (d.children && d.children.length > 0) {
      expandedKeys.push(d.key);
      getParentNodeKeys(d.children, expandedKeys);
    }
  });
};

const setExpandedKeysAll = (options, setExpandedKeys) => {
  const expandedKeys = [];
  getParentNodeKeys(options, expandedKeys);
  setExpandedKeys(expandedKeys);
};

const getRemoveNodeToParentSelectNode = (options, selectedKeys, key) => {
  let index = -1;
  for (let i = 0; i < options.length; i++) {
    if (options[i].key === key) {
      index = i;
      break;
    }
    else if (options[i].children) {
      if (getRemoveNodeToParentSelectNode(options[i].children, selectedKeys, key)) {
        selectedKeys.push(options[i].key);
        break;
      }
    }
  }
  if (index > -1) options.splice(index, 1);
  return index > -1;
};

const removeNode = (options, key, setOptions, setSelectedKeys) => {
  if (!key) return;

  const selectedKeys = [];
  getRemoveNodeToParentSelectNode(options, selectedKeys, key);

  setOptions(options.map(m => m));
  setSelectedKeys(selectedKeys);
};

const addTreeNode = (treeNode, options, setOptions, selectedKeys, setSelectedKeys, expandedKeys, setExpandedKeys) => {
  const selectNode = getSelectTreeNode(options, selectedKeys);
  if (selectNode == null) options.push(treeNode);
  else {
    treeNode.parentKey = selectNode.key;
    selectNode.children = selectNode.children || [];
    selectNode.children.push(treeNode);
  }
  selectedKeys = [treeNode.key];

  setOptions(options.map(m => m));
  setSelectedKeys(selectedKeys);
  if (selectNode && !expandedKeys.includes(selectNode.key)) {
    expandedKeys = expandedKeys.map(m => m);
    expandedKeys.push(selectNode.key);

    setExpandedKeys(expandedKeys);
  }
};

export default (props) => {
  const { property, view, pageAxis } = Base.getProps(props);

  const obj = useMemo(() => ({}), []);
  const [value, setValue] = useState(Base.getInitValue(property, obj));
  const [expandedKeys, setExpandedKeys] = useState([]);
  const [selectedKeys, setSelectedKeys] = useState([]);
  const [isVisible, setIsVisible] = useState(property.isVisible !== false);
  const [options, setOptions] = useGetDataSourceOptions(property, view, pageAxis, getOptions);

  const onCheck = useCallback((checkedKeys) => {
    setValue(checkedKeys);
  }, [setValue]);

  const onExpand = useCallback((keys) => {
    setExpandedKeys(keys);
  }, [setExpandedKeys]);

  const onSelect = useCallback((keys, e) => {
    if (property.isSingleSelect && keys.length === 0) return;
    if (property.isSelectValue) {
      // const selectValue = e.node.props.dataRef ? e.node.props.dataRef.value : e.node.props.value;
      // const parentValue = e.node.props.dataRef ? e.node.props.dataRef.parentValue : e.node.props.parentValue;

      // let list;
      // if (value.includes(selectValue)) {
      //   list = value.filter(f => f !== selectValue);
      //   if (value.includes(parentValue)) list = list.filter(f => f !== parentValue);
      // }
      // else {
      //   const childKeys = property.nodeKeys[parentValue];
      //   if (value.includes(parentValue) && property.nodeKeys[parentValue]) {
      //     list = value.filter(f => f !== parentValue);
      //     list = list.concat(childKeys.filter(f => f !== selectValue));
      //   }
      //   else {
      //     list = value.map(m => m);
      //     list.push(selectValue);
      //   }
      // }
      // setValue(list);

      const parentNode = e.nativeEvent.target.parentNode;
      if (parentNode.parentNode && parentNode.parentNode.childNodes.length > 2) parentNode.parentNode.childNodes[2].click();
    }
    else setSelectedKeys(keys);
  }, [property, setSelectedKeys]);

  useEffect(() => {
    if (property.selectedKeys !== selectedKeys) {
      property.selectedChange && property.selectedChange(getSelectTreeNode(options, selectedKeys));
      property.selectedKeys = selectedKeys;
    }
  }, [property, options, selectedKeys]);

  useEffect(() => {
    if (!obj.isFirstExpandAll && property.isExpandAll && options.length > 0) {
      obj.isFirstExpandAll = true;
      setExpandedKeysAll(options, setExpandedKeys);
    }
  }, [property, obj, options, setExpandedKeys]);

  property.treeObj = obj;
  property.setIsVisible = (v) => setIsVisible(v);
  property.getSelectTreeNode = (key) => getSelectTreeNode(options, [key]);
  property.removeNode = (key) => removeNode(options, key, setOptions, setSelectedKeys);
  property.refreshOptions = () => setOptions(options.map(m => m));
  property.getSelectedNode = () => getSelectTreeNode(options, selectedKeys);
  property.setSelectedKeys = (key) => setSelectedKeys([key]);

  if (property.isTreeNodes) {
    property.getValue = () => getTreeNodesValue(property, obj.treeNodesValue, value);
    property.setValue = (v) => setTreeNodesValue(property, obj, v, setOptions, selectedKeys, setSelectedKeys);
  }
  else if (property.isSelectNode) {
    property.setValue = (v) => setSelectedKeys(v || []);
    property.getValue = () => Base.getValue(property, setSelectedKeys);
  }
  else {
    property.setValue = (v) => setValue(v || []);
    property.getValue = () => Base.getValue(property, value);
  }

  property.setOptions = (v) => setOptions(v);
  property.addTreeNode = (node) => addTreeNode(node, options, setOptions, selectedKeys, setSelectedKeys, expandedKeys, setExpandedKeys);

  if (!isVisible) return null;

  let valueList = Common.isNullOrEmpty(value) ? [] : value;
  if (!Common.isArray(valueList)) valueList = valueList.split(",");

  if (options.length === 0) return null;

  const showLine = !!property.showLine;

  if (property.defaultExpandAll) {
    return <Tree
      checkable={property.isCheckBox}
      onCheck={onCheck}
      checkedKeys={valueList}
      onSelect={onSelect}
      showLine={showLine}
      defaultExpandAll={property.defaultExpandAll}
      selectedKeys={selectedKeys} treeData={options} />;
  }

  return <Tree
    checkable={property.isCheckBox}
    onExpand={onExpand}
    expandedKeys={expandedKeys}
    onCheck={onCheck}
    checkedKeys={valueList}
    onSelect={onSelect}
    showLine={showLine}
    selectedKeys={selectedKeys} treeData={options} />;
};